package com.ajavaer.framework.common.tools;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.*;
import java.util.function.Function;

public class ObjectTools {
    private static Logger log = LoggerFactory.getLogger(ObjectTools.class);

    public static boolean isBlank(Object o) {
        if (o == null) {
            return true;
        }
        if (o instanceof Collection) {
            return ((Collection) o).isEmpty();
        } else if (o instanceof Map) {
            return ((Map) o).isEmpty();
        } else if (o instanceof Object[]) {
            return ((Object[]) o).length == 0;
        } else if (o instanceof String) {
            return StringTools.isBlank(o.toString());
        }
        return false;
    }

    public static <K, V> Map<K, V> removeNull(Map<K, V> map) {
        Iterator<Map.Entry<K, V>> it = map.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry entry = it.next();
            if (entry.getKey() == null || entry.getValue() == null) {
                it.remove();
            }
        }
        return map;
    }

    public static <T> T nvl(T t, T defaultValue) {
        return t == null ? defaultValue : t;
    }

    /**
     * 抽出对象中的某一个字段列表
     *
     * @param list
     * @param function
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> List<R> fieldList(List<T> list, Function<T, R> function) {
        List<R> result = new ArrayList<>();
        for (T t : list) {
            R r = function.apply(t);
            result.add(r);
        }
        return result;
    }

    /**
     * 将对象列表转换为索引MAP
     *
     * @param list
     * @param function
     * @param <ID>
     * @param <T>
     * @return
     */
    public static <ID, T> Map<ID, T> index(List<T> list, Function<T, ID> function) {
        Map<ID, T> index = new HashMap<>();
        for (T t : list) {
            ID id = function.apply(t);
            index.put(id, t);
        }
        return index;
    }

    public static boolean isNotBlank(Object o) {
        return !isBlank(o);
    }

    /**
     * 反序列化
     *
     * @param bytes
     * @return
     */
    public static Object deserialize(byte[] bytes) {

        Object result = null;

        if (isEmpty(bytes)) {
            return null;
        }

        try {
            ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes);
            try {
                ObjectInputStream objectInputStream = new ObjectInputStream(byteStream);
                try {
                    result = objectInputStream.readObject();
                } catch (ClassNotFoundException ex) {
                    throw new Exception("Failed to deserialize object type", ex);
                }
            } catch (Throwable ex) {
                throw new Exception("Failed to deserialize", ex);
            }
        } catch (Exception e) {
            log.error("Failed to deserialize", e);
        }
        return result;
    }

    public static boolean isEmpty(byte[] data) {
        return (data == null || data.length == 0);
    }

    /**
     * 序列化
     *
     * @param object
     * @return
     */
    public static byte[] serialize(Object object) {

        byte[] result = null;

        if (object == null) {
            return new byte[0];
        }
        try {
            ByteArrayOutputStream byteStream = new ByteArrayOutputStream(128);
            try {
                if (!(object instanceof Serializable)) {
                    throw new IllegalArgumentException(ObjectTools.class.getSimpleName() + " requires a Serializable payload " +
                            "but received an object of type [" + object.getClass().getName() + "]");
                }
                ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteStream);
                objectOutputStream.writeObject(object);
                objectOutputStream.flush();
                result = byteStream.toByteArray();
            } catch (Throwable ex) {
                throw new Exception("Failed to serialize", ex);
            }
        } catch (Exception ex) {
            log.error("Failed to serialize", ex);
        }
        return result;
    }
}
